package cn.wolfcode.luowowo.search.service.impl;

import cn.wolfcode.luowowo.search.query.SearchQueryObject;
import cn.wolfcode.luowowo.search.service.ISearchService;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import org.apache.commons.beanutils.BeanUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl implements ISearchService {

    @Autowired
    private ElasticsearchTemplate template;

    @Override
    public <T> Page<T> searchWithHighlight(Class<T> clz, SearchQueryObject qo, String... fields) {
        String preTag = "<span style='color:red'>";
        String postTag = "</span>";
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();

        HighlightBuilder.Field[] higField = new HighlightBuilder.Field[fields.length];
        for (int i = 0; i < fields.length; i++) {
            higField[i] = new HighlightBuilder.Field(fields[i]).preTags(preTag).postTags(postTag);
        }
        builder.withHighlightFields(higField);
        builder.withQuery(QueryBuilders.multiMatchQuery(qo.getKeyword(), fields));

        return template.queryForPage(builder.build(), clz, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
                SearchHits hit = response.getHits();
                SearchHit[] hits = hit.getHits();
                List<T> list = new ArrayList<>();
                for (SearchHit sh : hits) {
                    T t = JSON.parseObject(sh.getSourceAsString(), aClass);
                    setHighlight(sh.getHighlightFields(), t);
                    list.add(t);
                }
                return new AggregatedPageImpl<>(list, pageable, hit.getTotalHits());
            }
        });
    }

    private <T> void setHighlight(Map<String, HighlightField> highlightFields, T t) {
        for (String key : highlightFields.keySet()) {
            try {
                BeanUtils.setProperty(t, key, highlightFields.get(key).fragments()[0].toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
